import com.google.gson.Gson
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import org.xbill.DNS.Address
import java.io.IOException
import java.net.InetAddress
import java.util.regex.Pattern

class DNSHelper(
    private val domain: String,
    private val subDomain: String,
    private val apiId: String,
    private val apiToken: String
) {
    companion object {
        val CHECK_URL = arrayOf(
            "https://ip.03k.org",
            "https://myip.ipip.net/",
            "https://api-ipv4.ip.sb/ip",
            "https://checkip.dns.he.net/"
        )
        val NAMESERVER = arrayOf(
            "119.29.29.29", // DNSPod
            "8.8.8.8",
            "114.114.114.114"
        )
        const val IP_REGEX = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}"
    }

    private val client = OkHttpClient()

    fun getUrlIp(): String? {
        for (checkUrl in CHECK_URL) {
            val urlIp = getUrlIp(checkUrl)
            if (urlIp != null) {
                return urlIp
            }
        }
        return null
    }

    private fun getUrlIp(checkUrl: String): String? {
        try {
            val request = Request.Builder().url(checkUrl).build()
            val response = client.newCall(request).execute()
            if (response.isSuccessful) {
                val content = response.body!!.string()
                val matcher = Pattern.compile(IP_REGEX).matcher(content)
                if (matcher.find()) {
                    return matcher.group()
                }
            }
        } catch (e: IOException) {
            Logger.d(e)
        }
        return null
    }

    fun getDnsIp(): String? {
        val systemResult = getDnsIpBySystem()
        if (systemResult != null) {
            return systemResult
        }
        return getDnsIpByLib()
    }

    private fun getDnsIpBySystem(): String? {
        try {
            val address = InetAddress.getByName("$subDomain.$domain")
            return address.hostAddress
        } catch (e: IOException) {
            Logger.d(e)
        }
        return null
    }

    private fun getDnsIpByLib(): String? {
        System.setProperty("dns.server", NAMESERVER.joinToString(separator = ",") { it })
        return Address.getByName("$subDomain.$domain")?.hostAddress
    }

    fun getDnspodIp(): RecordListResponse.Record? {
        try {
            val body = FormBody.Builder()
                .add("login_token", "$apiId,$apiToken")
                .add("format", "json")
                .add("lang", "cn")
                .add("error_on_empty", "no")
                .add("domain", domain)
                .add("sub_domain", subDomain)
                .add("record_type", "A")

            val request = Request.Builder().url("https://dnsapi.cn/Record.List").post(body.build()).build()
            val response = client.newCall(request).execute()
            if (response.isSuccessful) {
                val entity = Gson().fromJson(response.body!!.string(), RecordListResponse::class.java)
                if (entity.status?.code == 1) {
                    if (entity.records != null && entity.records.isNotEmpty()) {
                        if (entity.records.size > 1) {
                            Logger.w(entity.toString())
                        }
                        return entity.records[0]
                    }
                    return null
                } else {
                    Logger.e(entity.status?.message)
                }
            }
        } catch (e: IOException) {
            Logger.d(e)
        }
        return null
    }

    fun updateDnspodIp(record: RecordListResponse.Record, ip: String): Boolean {
        val body = FormBody.Builder()
            .add("login_token", "$apiId,$apiToken")
            .add("format", "json")
            .add("lang", "cn")
            .add("error_on_empty", "no")
            .add("domain", domain)
            .add("sub_domain", subDomain)
            .add("record_id", record.id)
            .add("record_type", record.type)
            .add("record_line", record.line)
            .add("record_line_id", record.line_id)
            .add("value", ip)
        val request = Request.Builder().url("https://dnsapi.cn/Record.Modify").post(body.build()).build()
        val response = client.newCall(request).execute()
        if (response.isSuccessful) {
            val entity = Gson().fromJson(response.body!!.string(), Response::class.java)
            if (entity.status?.code != 1) {
                Logger.e(entity.status?.message)
            } else {
                return true
            }
        }
        return false
    }
}